home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / programm.ing / m2posx10.zoo / m2posix.10 / src / lib.ipp < prev    next >
Encoding:
Modula Implementation  |  1993-12-02  |  20.5 KB  |  662 lines

  1. IMPLEMENTATION MODULE lib;
  2. __IMP_SWITCHES__
  3. #ifdef HM2
  4. #ifdef __LONG_WHOLE__
  5. (*$!i+: Modul muss mit $i- uebersetzt werden! *)
  6. (*$!w+: Modul muss mit $w- uebersetzt werden! *)
  7. #else
  8. (*$!i-: Modul muss mit $i+ uebersetzt werden! *)
  9. (*$!w-: Modul muss mit $w+ uebersetzt werden! *)
  10. #endif
  11. #endif
  12. (*****************************************************************************)
  13. (* Die Funktion "rand()" ist eine direkte Umsetzung aus der GnuLib/MiNTLib.  *)
  14. (*---------------------------------------------------------------------------*)
  15. (* 27-Nov-93, Holger Kleinschmidt                                            *)
  16. (*****************************************************************************)
  17.  
  18. VAL_INTRINSIC
  19. CAST_IMPORT
  20. PTR_ARITH_IMPORT
  21.  
  22. FROM SYSTEM IMPORT
  23. (* TYPE *) ADDRESS,
  24. (* PROC *) ADR;
  25.  
  26. FROM PORTAB IMPORT
  27. (* TYPE *) UNSIGNEDLONG, SIGNEDLONG, UNSIGNEDWORD;
  28.  
  29. FROM ctype IMPORT
  30. (* PROC *) todigit, tocard, toupper, isspace;
  31.  
  32. FROM types IMPORT
  33. (* CONST*) NULL;
  34.  
  35. IMPORT e;
  36.  
  37. FROM MEMBLK IMPORT
  38. (* PROC *) memswap;
  39.  
  40. #ifdef TSM2_1
  41. FROM AsmLib IMPORT SetJmp, LongJmp;
  42. #endif
  43.  
  44. (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
  45.  
  46. CONST
  47.   MINLINT  = 80000000H;
  48.   MAXLINT  = 7FFFFFFFH;
  49.   MAXLCARD = 0FFFFFFFFH;
  50.  
  51. VAR
  52.   Seed : SIGNEDLONG;
  53.  
  54. (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
  55.  
  56. PROCEDURE lfind ((* EIN/ -- *) key     : ADDRESS;
  57.                  (* EIN/ -- *) base    : ADDRESS;
  58.                  (* EIN/ -- *) nelems  : UNSIGNEDLONG;
  59.                  (* EIN/ -- *) size    : UNSIGNEDLONG;
  60.                  (* EIN/ -- *) compare : CompareProc  ): ADDRESS;
  61. (*T*)
  62. VAR last : ADDRESS;
  63.  
  64. BEGIN
  65.  IF (key = NULL) OR (base = NULL) OR (size = LC(0)) OR (nelems = LC(0)) THEN
  66.    RETURN(NULL);
  67.  END;
  68.  
  69.  last := ADDADR(base, (nelems - LC(1)) * size);
  70.  
  71.  (* Indem das letzte zu vergleichende Feldelement
  72.   * mit dem zu suchenden ausgetauscht wird, wirkt
  73.   * es als Endemarke fuer das Suchen.
  74.   *)
  75.  memswap(key, last, size);
  76.  
  77.  WHILE compare(base, last) <> 0  DO
  78.    base := ADDADR(base, size);
  79.  END;
  80.  
  81.  (* Das Vertauschen muss natuerlich wieder rueckgaengig gemacht werden. *)
  82.  memswap(key, last, size);
  83.  
  84.  (* Wenn das gesamte Feld durchsucht wurde, muss noch
  85.   * der Vergleich mit dem letzten Element erfolgen,
  86.   * ansonsten wurde schon vorher ein Element mit dem
  87.   * gesuchten Wert gefunden.
  88.   *)
  89.  IF (base = last) AND (compare(last, key) <> 0) THEN
  90.    RETURN(NULL);
  91.  ELSE
  92.    RETURN(base);
  93.  END;
  94. END lfind;
  95.  
  96. (*---------------------------------------------------------------------------*)
  97.  
  98. PROCEDURE bsearch ((* EIN/ -- *) key     : ADDRESS;
  99.                    (* EIN/ -- *) base    : ADDRESS;
  100.                    (* EIN/ -- *) nelems  : UNSIGNEDLONG;
  101.                    (* EIN/ -- *) size    : UNSIGNEDLONG;
  102.                    (* EIN/ -- *) compare : CompareProc  ): ADDRESS;
  103. (*T*)
  104. VAR __REG__ left  : UNSIGNEDLONG;
  105.     __REG__ right : UNSIGNEDLONG;
  106.     __REG__ mid   : UNSIGNEDLONG;
  107.  
  108. BEGIN
  109.  IF (key = NULL) OR (base = NULL) OR (size = LC(0)) OR (nelems = LC(0)) THEN
  110.    RETURN(NULL);
  111.  END;
  112.  
  113.  left  := 0;
  114.  right := nelems - LC(1);
  115.  
  116.  WHILE left < right DO
  117.    mid := (left + right) DIV LC(2);
  118.    (* left <= mid < right *)
  119.    IF compare(ADDADR(base, mid * size), key) < 0 THEN
  120.      left  := mid + LC(1);
  121.    ELSE
  122.      right := mid;
  123.    END;
  124.  END;
  125.  
  126.  base := ADDADR(base, left * size);
  127.  IF compare(base, key) = 0 THEN
  128.    RETURN(base);
  129.  ELSE
  130.    RETURN(NULL);
  131.  END;
  132. END bsearch;
  133.  
  134. (*---------------------------------------------------------------------------*)
  135.  
  136. PROCEDURE qsort ((* EIN/ -- *) base    : ADDRESS;
  137.                  (* EIN/ -- *) nelems  : UNSIGNEDLONG;
  138.                  (* EIN/ -- *) size    : UNSIGNEDLONG;
  139.                  (* EIN/ -- *) compare : CompareProc  );
  140. (*T*)
  141. CONST direct = LC(8);
  142.  
  143. VAR cmpP : ADDRESS;
  144.  
  145. VAR rP : ADDRESS;
  146.     (* wird bei Selectionsort benutzt, und ist hier deklariert,
  147.      * damit er keinen Stackplatz beim rekursiven Aufruf von "sort()"
  148.      * belegt. Er braucht keine lokale Variable von "sort()" zu sein,
  149.      * da er nur vom Selectionsort benutzt werden, aus dem heraus kein
  150.      * weiterer rekursiver Aufruf mehr stattfindet.
  151.      *)
  152.  
  153. (* Das Prinzip von Quicksort ist an sich recht einfach:
  154.  
  155.    Als erstes wird ein beliebiges Element des Feldes ausgewaehlt, dann
  156.    werden von beiden Enden des Feldes zur Mitte hin Elemente gesucht, die
  157.    groesser bzw. kleiner oder gleich dem Vergleichselement sind - diese
  158.    beiden Elemente werden ausgetauscht; das Austauschen wird solange
  159.    wiederholt, bis sich die beiden Suchzeiger ueberschneiden; In der linken
  160.    Haelfte befinden sich dann die Elemente, die kleiner oder gleich dem
  161.    Vergleichselement sind, in der rechten Haelfte befinden sich die Elemente,
  162.    die groesser oder gleich dem Vergleichselement sind.
  163.    Diese Prozedur wird jetzt mit den beiden Haelften erneut ausgefuehrt
  164.    usw. bis die zu sortierenden Teilfelder nur noch ein Element gross sind,
  165.    dann ist das gesamte Feld sortiert. Die wiederholte Ausfuehrung gleicher
  166.    Taetigkeiten schreit natuerlich nach Rekursion.
  167.  
  168.    Der Aufwand:
  169.  
  170.    Den Partitionierungsvorgang kann man sich als das Suchen eines bestimmten
  171.    Elementes, naemlich das mit dem naechstgroesseren Wert, vorstellen.
  172.    Angenommen, das Vergleichselement ist immer das wertemaessig mittlere
  173.    Element: in diesem Fall wird die Suche zur Binaersuche, da immer die
  174.    Haelfte der Werte beim naechsten Suchvorgang ausgeschlossen wird. Der
  175.    Aufwand des binaeren Suchens betraegt  O( ld( n )); da wir n Elemente
  176.    haben, betraegt der Sortieraufwand O( n * ld( n )).
  177.    Das waere der Idealfall.
  178.  
  179.    Im schlechtesten Fall ist das ausgewaehlte Vergleichselement immer das
  180.    wertemaessig groesste bzw. kleinste; in diesem Fall wird die Suche zur
  181.    linearen Suche, deren mittlerer Aufwand  n/2 betraegt; der Aufwand des
  182.    Sortierens betraegt dann  O( n * n ). Ein Beispiel waere ein bereits
  183.    sortiertes Feld, bei dem man als Vergleichselement immer das erste
  184.    auswaehlt.
  185.  
  186.    Den schlechtesten Fall kann man zwar nicht ganz ausschliessen, aber
  187.    doch sehr unwahrscheinlich machen: die einfachste Methode ist, als
  188.    Vergleichselement das positionsmaessig mittlere zu nehmen; die
  189.    Wahrscheinlichkeit hierbei haeufig die Extremwerte zu erwischen ist
  190.    gering. Noch unwahrscheinlicher wird es, wenn als Vergleichselement das
  191.    wertemaessig mittlere aus dreien genommen wird (z.B. dem positionsmaessig
  192.    ersten, mittleren und letzten).
  193.  
  194.    Abgesehen von der Wahl des Vergleichselementes gibt es weitere
  195.    Moeglichkeiten zur Optimierung:
  196.  
  197.     - Zuerst die kleinere Haelfte weitersortieren.
  198.       Hierdurch betraegt die Stackbelastung nur  ~ld(n).
  199.  
  200.     - Hinter dem rekursiven Aufruf zur Sortierung der zweiten, groesseren
  201.       Haelfte folgt kein Ausdruck, der vom Ergebnis dieses Aufrufs abhaengt;
  202.       die Sortierung der groesseren Feldes kann deswegen iterativ geschehen.
  203.  
  204.     - Wie alle hoeheren Sortiermethoden ist auch bei Quicksort die Leistung
  205.       bei kleinem  n  schwach, da der Verwaltungsaufwand relativ gross ist.
  206.       Unterschreitet daher die Groesse des zu sortierenden Teilfeldes ein
  207.       hinreichend kleines  n, kann das Feld durch eine einfachere Methode
  208.       (direktes Einfuegen, direkte Auswahl...) zuende sortiert werden.
  209. *)
  210.  
  211. PROCEDURE sort ((* EIN/ -- *) bot : UNSIGNEDLONG;
  212.                 (* EIN/ -- *) top : UNSIGNEDLONG );
  213.  
  214. VAR         left   : UNSIGNEDLONG;
  215.             right  : UNSIGNEDLONG;
  216.     __REG__ leftP  : ADDRESS;
  217.     __REG__ rightP : ADDRESS;
  218.  
  219. BEGIN (* sort *)
  220.  WHILE bot < top DO
  221.    left   := bot;
  222.    right  := top;
  223.    leftP  := ADDADR(base, bot * size);
  224.    rightP := ADDADR(base, top * size);
  225.  
  226.    IF top - bot < direct THEN
  227.      (* Direktes Sortieren durch Auswaehlen.
  228.       * 'SelectionSort' ist bei so wenigen Elementen
  229.       * (< 10) schneller als 'InsertionSort'.
  230.       *
  231.       * Funktionsweise:
  232.       * Der Reihe nach vom ersten bis zum vorletzten
  233.       * Element wird ein Vergleichselement gewaehlt,
  234.       * das mit allen Elementen rechts von ihm verglichen
  235.       * wird; das Minimum und das Vergleichselement
  236.       * werden ausgetauscht.
  237.       *)
  238.  
  239.      WHILE DIFADR(leftP, rightP) < LIC(0) DO
  240.        cmpP := leftP;
  241.        rP   := ADDADR(leftP, size);
  242.        WHILE DIFADR(rP, rightP) <= LIC(0) DO
  243.          IF compare(rP, cmpP) < 0 THEN
  244.            cmpP := rP;
  245.          END;
  246.          rP := ADDADR(rP, size);
  247.        END; (* WHILE *)
  248.  
  249.        IF cmpP <> leftP THEN
  250.          memswap(cmpP, leftP, size);
  251.        END;
  252.        leftP := ADDADR(leftP, size);
  253.      END;
  254.      RETURN; (* fertig *)
  255.  
  256.    ELSE
  257.  
  258.      (* Es wird kein groesserer Aufwand bei der Auswahl des
  259.       * mittleren Elementes betrieben, da dies in den allermeisten
  260.       * Faellen mehr Zeit kostet, als es Zeit einspart, wenn das
  261.       * Feld wirklich so unguenstig belegt ist, dass das
  262.       * positionsmaessig mittlere immer das Extremelement ist.
  263.       *)
  264.  
  265.      cmpP := ADDADR(base, ((left + right) DIV LC(2)) * size);
  266.  
  267.      REPEAT
  268.  
  269.        (* Bei der Suche nach den auszutauschenden Elementen gibt es
  270.         * zwei Moeglichkeiten:
  271.         *
  272.         *  - Vom jeweiligen Rand ausgehend wird ein Element gesucht,
  273.         *    dass groesser/kleiner ODER GLEICH dem Vergleichselement
  274.         *    ist. Durch die Gleichbedingung wirkt das Vergleichselement
  275.         *    als Endemarke der Iteration, da auf jeden Fall dieses
  276.         *    Element gefunden wird.
  277.         *    Der Nachteil: Kommt der Wert des Vergleichselementes
  278.         *    haufig in dem Feld vor, so finden entsprechend viele
  279.         *    unnoetige Austauschoperationen statt.
  280.         *
  281.         *  - Vom jeweiligen Rand her wird ein Element gesucht, dass
  282.         *    ECHT groesser (kleiner) als das Vergleichselement ist.
  283.         *    Das vermeidet die unnoetigen Austauschoperationen bei
  284.         *    Elementen, die gleich dem Vergleichselement sind;
  285.         *    allerdings wirkt das Vergleichselement nun nicht mehr
  286.         *    als Marke (es kann sein, dass kein Element gefunden
  287.         *    wird, das echt groesser/kleiner als das Vergleichselement
  288.         *    ist), sodass zusaetzlich der Laufindex als Endebedingung
  289.         *    abgefragt werden muss.
  290.         *
  291.         * Es wird die erste Methode benutzt, da eine grosse Anzahl
  292.         * von Elementen mit gleichem Schluessel sicher selten vorkommt,
  293.         * und bei der zweiten Methode dafuer an anderer Stelle mehr
  294.         * Aufwand getrieben werden muss.
  295.         *)
  296.  
  297.        WHILE compare(leftP, cmpP) < 0 DO
  298.          leftP := ADDADR(leftP, size);
  299.          INC(left);
  300.        END;
  301.  
  302.        WHILE compare(cmpP, rightP) < 0 DO
  303.          rightP := SUBADR(rightP, size);
  304.          DEC(right);
  305.        END;
  306.  
  307.        IF left <= right THEN
  308.          memswap(leftP, rightP, size);
  309.          (* Falls das Vergleichselement beim Austausch beteiligt war,
  310.           * muss auch der Zeiger auf das Vergleichselement entsprechend
  311.           * neu gesetzt werden.
  312.           *)
  313.          IF cmpP = leftP THEN
  314.            cmpP := rightP;
  315.          ELSIF cmpP = rightP THEN
  316.            cmpP := leftP;
  317.          END;
  318.  
  319.          IF left < top THEN
  320.            INC(left);
  321.            leftP := ADDADR(leftP, size);
  322.          END;
  323.          IF right > bot THEN
  324.            DEC(right);
  325.            rightP := SUBADR(rightP, size);
  326.          END;
  327.        END;
  328.      UNTIL left > right;
  329.  
  330.      (* (bot<=i<left)->(x[i]<=x[cmpP]) & (right<i<=top)->(x[i]>=x[cmpP]) *)
  331.  
  332.      IF (right - bot) < (top - left) THEN
  333.        (* Nur das kleinere Teilfeld wird rekursiv
  334.         * weitersortiert, das groessere wird durch
  335.         * die darauffolgenden Zuweisungen in der
  336.         * Schleife weiter zerlegt.
  337.         *)
  338.        IF bot < right THEN
  339.          (* Rekursionsbasis: Teilfeld ist sortiert,
  340.           * wenn es nur noch ein Element enthaelt.
  341.           *)
  342.          sort(bot, right);
  343.        END;
  344.        (* Die Elemente left von <left> sind jetzt sortiert,
  345.         * die groessere Haelfte wird in der Schleife
  346.         * weiterbearbeitet.
  347.         *)
  348.        bot := left;
  349.      ELSE
  350.        IF left < top THEN
  351.          sort(left, top);
  352.        END;
  353.        top := right;
  354.      END; (* IF (right ..*)
  355.  
  356.    END; (* IF (top ..*)
  357.  END; (* WHILE *)
  358. END sort;
  359.  
  360. BEGIN (* qsort *)
  361.  IF (base = NULL) OR (size = LC(0)) OR (nelems <= LC(1)) THEN
  362.    RETURN;
  363.  END;
  364.  sort(0, nelems - LC(1));
  365. END qsort;
  366.  
  367. (*---------------------------------------------------------------------------*)
  368.  
  369. PROCEDURE ValToStr ((* EIN/ -- *)     val    : UNSIGNEDLONG;
  370.                     (* EIN/ -- *)     signed : BOOLEAN;
  371.                     (* EIN/ -- *)     base   : CARDINAL;
  372.                     (* -- /AUS *) VAR str    : ARRAY OF CHAR );
  373. (*T*)
  374. VAR         basis  : UNSIGNEDLONG;
  375.     __REG__ len    : UNSIGNEDWORD;
  376.     __REG__ i      : UNSIGNEDWORD;
  377.             sign   : BOOLEAN;
  378.             digits : ARRAY [0..33] OF CHAR;
  379.  
  380. BEGIN
  381.  IF (base < 2) OR (base > 36) THEN
  382.    basis := 10;
  383.  ELSE
  384.    basis := VAL(UNSIGNEDLONG,base);
  385.  END;
  386.  
  387.  sign := signed AND (base = 10) AND (CAST(SIGNEDLONG,val) < LIC(0));
  388.  IF sign THEN
  389.    IF val <> MINLINT THEN
  390.      (* Abfrage verhindert Ueberlauffehler, da MINLINT im
  391.       * Zweierkomplement nicht als positive Zahl darstellbar ist
  392.       * und unveraendert bleibt.
  393.       *)
  394.      val := CAST(UNSIGNEDLONG,-CAST(SIGNEDLONG,val));
  395.    END;
  396.  END;
  397.  
  398.  (* Die Zahl von hinten nach vorne in String wandeln;
  399.   * durch die REPEAT-Schleife wird auch die Null
  400.   * dargestellt.
  401.   *)
  402.  len := 0;
  403.  REPEAT
  404.    digits[len] := toupper(todigit(VAL(CARDINAL,val MOD basis)));
  405.    val    := val DIV basis;
  406.    INC(len);
  407.  UNTIL val = LC(0);
  408.  IF sign THEN
  409.    digits[len] := '-';
  410.    INC(len);
  411.  END;
  412.  
  413.  
  414.  IF len > VAL(UNSIGNEDWORD,HIGH(str)) THEN
  415.    len := VAL(UNSIGNEDWORD,HIGH(str) + 1);
  416.  ELSE
  417.    str[len] := 0C;
  418.  END;
  419.  
  420.  (* Jetzt wird die Zahlendarstellung in umgekehrter
  421.   * Reihenfolge aus dem Hilfsstring in den eigentlichen
  422.   * String uebertragen. Ausserdem werden Prefix und fuehrende
  423.   * Nullen hinzugefuegt.
  424.   *)
  425.  
  426.  i := 0;
  427.  WHILE len > 0 DO
  428.    DEC(len);
  429.    str[i] := digits[len];
  430.    INC(i);
  431.  END;
  432. END ValToStr;
  433.  
  434. (*---------------------------------------------------------------------------*)
  435.  
  436. PROCEDURE ltoa ((* EIN/ -- *)     num  : SIGNEDLONG;
  437.                 (* -- /AUS *) VAR str  : ARRAY OF CHAR;
  438.                 (* EIN/ -- *)     base : CARDINAL      );
  439. (*T*)
  440. BEGIN
  441.  ValToStr(CAST(UNSIGNEDLONG,num), TRUE, base, str);
  442. END ltoa;
  443.  
  444. (*---------------------------------------------------------------------------*)
  445.  
  446. PROCEDURE ultoa ((* EIN/ -- *)     num  : UNSIGNEDLONG;
  447.                  (* -- /AUS *) VAR str  : ARRAY OF CHAR;
  448.                  (* EIN/ -- *)     base : CARDINAL      );
  449. (*T*)
  450. BEGIN
  451.  ValToStr(num, FALSE, base, str);
  452. END ultoa;
  453.  
  454. (*---------------------------------------------------------------------------*)
  455.  
  456. PROCEDURE StrToVal ((* EIN/ -- *) VAR str     : ARRAY OF CHAR;
  457.                     (* EIN/ -- *)     max     : UNSIGNEDLONG;
  458.                     (* EIN/ -- *)     basis   : CARDINAL;
  459.                     (* EIN/ -- *)     signed  : BOOLEAN;
  460.                     (* -- /AUS *) VAR nextIdx : CARDINAL;
  461.                     (* -- /AUS *) VAR val     : UNSIGNEDLONG  );
  462. (*T*)
  463. VAR __REG__ idx          : UNSIGNEDWORD;
  464.     __REG__ digit        : CHAR;
  465.             neg          : BOOLEAN;
  466.             maxDivBase   : UNSIGNEDLONG;
  467.             maxLastDigit : UNSIGNEDLONG;
  468.             num          : UNSIGNEDLONG;
  469.             base         : UNSIGNEDLONG;
  470.  
  471. BEGIN
  472.  val := 0;
  473.  idx := 0;
  474.  neg := FALSE;
  475.  
  476.  (* Fuehrende Leerzeichen tun nichts zur Sache *)
  477.  WHILE (idx <= VAL(UNSIGNEDWORD,HIGH(str))) AND isspace(str[idx]) DO
  478.    INC(idx);
  479.  END;
  480.  
  481.  (* Moegliches Vorzeichen feststellen, bei negativer Zahl ist der
  482.   * maximale Wert um eins groesser (im Zweierkomplement).
  483.   *)
  484.  IF signed AND (idx <= VAL(UNSIGNEDWORD,HIGH(str))) THEN
  485.    digit := str[idx];
  486.    neg   := digit = '-';
  487.    IF digit = '+' THEN
  488.      INC(idx);
  489.    ELSIF neg THEN
  490.      (* Negative Zahlen haben einen um eins groesseren
  491.       * Wertebereich als positive Zahlen (die Null ausgenommen).
  492.       *)
  493.      INC(idx);
  494.      INC(max);
  495.    END;
  496.  END;
  497.  
  498.  (* Keine Zahl kann folgen => Fehler *)
  499.  IF idx > VAL(UNSIGNEDWORD,HIGH(str)) THEN
  500.    nextIdx := idx;
  501.    RETURN;
  502.  END;
  503.  
  504.  IF (basis < 2) OR (basis > 36) THEN
  505.    basis := 0;
  506.  END;
  507.  base  := VAL(UNSIGNEDLONG,basis);
  508.  digit := str[idx];
  509.  
  510.  IF basis = 0 THEN
  511.    (* Die Basis der Zahl soll aus der Zeichenfolge hervorgehen *)
  512.    INC(idx);
  513.    IF digit = '%' THEN
  514.      (* Zahl in Binaerdarstellung *)
  515.      base := 2;
  516.    ELSIF digit = '0' THEN
  517.      (* Zahl in Sedezimal- oder Oktaldarstellung oder einzelne Null *)
  518.      IF (idx <= VAL(UNSIGNEDWORD,HIGH(str))) AND (toupper(str[idx]) = 'X') THEN
  519.        base := 16;
  520.        INC(idx);
  521.      ELSE
  522.        base := 8;
  523.      END;
  524.    ELSIF digit = '$' THEN
  525.      base := 16;
  526.    ELSE
  527.      base := 10;
  528.      DEC(idx);
  529.    END;
  530.  
  531.  (* Die Basis ist angegeben, zusaetzliche Angabe in Repraesentation
  532.   * ueberlesen (Oktalnull stoert nicht).
  533.   *)
  534.  ELSIF (basis = 2) AND (digit = '%') THEN
  535.    (* Binaerdarstellung *)
  536.    INC(idx);
  537.  ELSIF basis = 16 THEN
  538.    (* Sedezimaldarstellung *)
  539.    IF digit = '$' THEN
  540.      INC(idx);
  541.    ELSIF  (digit = '0')
  542.       AND (idx < VAL(UNSIGNEDWORD,HIGH(str)))
  543.       AND (toupper(str[idx+1]) = 'X')
  544.    THEN
  545.      INC(idx, 2);
  546.    END;
  547.  END;
  548.  
  549.  maxDivBase   := max DIV base;
  550.  maxLastDigit := max MOD base;
  551.  
  552.  LOOP
  553.    (* Abbrechen, sobald der String zuende ist, oder ein Zeichen gefunden
  554.     * wurde, das keine gueltige Ziffer ist, oder ein Ueberlauf stattfinden
  555.     * wuerde.
  556.     *)
  557.    nextIdx := idx;
  558.    IF idx > VAL(UNSIGNEDWORD,HIGH(str)) THEN
  559.      EXIT;
  560.    END;
  561.  
  562.    digit := str[idx];
  563.    num   := VAL(UNSIGNEDLONG,tocard(digit));
  564.    IF num >= base THEN
  565.      EXIT;
  566.    END;
  567.  
  568.    (* Da <val> mit jedem neuen Digit um eine Stelle erweitert wird,
  569.     * wird fuer die Ueberlaufpruefung der bisherige <val> vor der
  570.     * Erweiterung mit einem Zehntel des Maximalvales verglichen;
  571.     * wuerde nach der Erweiterung verglichen, waere der Ueberlauf
  572.     * ja womoeglich schon passiert, und dabei koennte auch ein
  573.     * UNSIGNEDLONG-Ueberlauf auftreten -- ein Vergleich wuerde dann
  574.     * nur Unsinn produzieren.
  575.     * Ist der bisherige Wert kleiner als ein Zehntel des Maximums,
  576.     * kann kein Ueberlauf auftreten, ist der bisherige Wert gleich
  577.     * dem Maximumszehntel, muss geprueft werden, ob das neue Digit
  578.     * den Wert des letzten Digits des Maximums ueberschreitet.
  579.     *)
  580.    IF    (val < maxDivBase)
  581.       OR (val = maxDivBase) AND (num <= maxLastDigit)
  582.    THEN
  583.      val := val * base + num;
  584.      INC(idx);
  585.    ELSE (* Ueberlauf *)
  586.      e.errno := e.ERANGE;
  587.      IF neg AND (max <> MINLINT) THEN
  588.        val := CAST(UNSIGNEDLONG,-CAST(SIGNEDLONG,max));
  589.      ELSE
  590.        val := max;
  591.      END;
  592.      RETURN;
  593.    END;
  594.  END; (* LOOP *)
  595.  
  596.  IF neg AND (val <> MINLINT) THEN
  597.    (* Wenn vor der Zahl ein '-' stand und negative Zahlen erlaubt
  598.     * sind, den bisher positiven Zahlenwert in einen negativen wandeln.
  599.     * Abfrage auf MINLINT verhindert Ueberlauf.
  600.     *)
  601.    val := CAST(UNSIGNEDLONG,-CAST(SIGNEDLONG,val));
  602.  END;
  603. END StrToVal;
  604.  
  605. (*---------------------------------------------------------------------------*)
  606.  
  607. PROCEDURE strtol ((* EIN/ -- *) REF str  : ARRAY OF CHAR;
  608.                   (* -- /AUS *) VAR end  : CARDINAL;
  609.                   (* EIN/ -- *)     base : CARDINAL      ): SIGNEDLONG;
  610. (*T*)
  611. VAR val : UNSIGNEDLONG;
  612.  
  613. BEGIN
  614.  StrToVal(str, MAXLINT, base, TRUE, end, val);
  615.  RETURN(CAST(SIGNEDLONG,val));
  616. END strtol;
  617.  
  618. (*---------------------------------------------------------------------------*)
  619.  
  620. PROCEDURE strtoul ((* EIN/ -- *) REF str  : ARRAY OF CHAR;
  621.                    (* -- /AUS *) VAR end  : CARDINAL;
  622.                    (* EIN/ -- *)     base : CARDINAL      ): UNSIGNEDLONG;
  623. (*T*)
  624. VAR val : UNSIGNEDLONG;
  625.  
  626. BEGIN
  627.  StrToVal(str, MAXLCARD, base, FALSE, end, val);
  628.  RETURN(val);
  629. END strtoul;
  630.  
  631. (*---------------------------------------------------------------------------*)
  632.  
  633. PROCEDURE rand ( ): UNSIGNEDLONG;
  634. (*T*)
  635. CONST
  636.   A = LIC(16807);
  637.   M = LIC(2147483647);
  638.   Q = LIC(127773);
  639.   R = LIC(2836);
  640.  
  641. BEGIN
  642.  Seed := A * (Seed MOD Q) - R * (Seed DIV Q);
  643.  IF Seed < LIC(0) THEN
  644.    INC(Seed, M);
  645.  END;
  646.  RETURN(CAST(UNSIGNEDLONG,Seed));
  647. END rand;
  648.  
  649. (*---------------------------------------------------------------------------*)
  650.  
  651. PROCEDURE srand ((* EIN/ -- *) seed : UNSIGNEDLONG );
  652. (*T*)
  653. BEGIN
  654.  Seed := CAST(SIGNEDLONG,seed);
  655. END srand;
  656.  
  657. (*===========================================================================*)
  658.  
  659. BEGIN (* lib *)
  660.  Seed := 1;
  661. END lib.
  662.